{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 列表（list）\n",
    "**[hawksoft13320218299](http://github.com/xingyongkang)**\n",
    "## 简介\n",
    "list是python内建的一个class对象，根据需要，我们可以生成任意多个list对象。你可以把一个list对象想成一个仓库，这个仓库里可以放进多个对象，并对这些对象进行有效管理。它具有如下特点：\n",
    "- 为了有效管理这些对象，它把仓库分成多个位置，并给每个位置编上号，编号从0开始。\n",
    "- 每个位置只能放一个对象。\n",
    "- 对象可以放入，也可以被拿出。\n",
    "- 该仓库的容量是变化的。  最少可以没有对象，最多则没有上限，可以放任意多的对象。\n",
    "\n",
    "\n",
    "根据这些描述，你可以想象list对象该有那些功能，那么，该对象即提供了对应的方法。我们首先用`dir`函数看一下。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__add__',\n",
       " '__class__',\n",
       " '__contains__',\n",
       " '__delattr__',\n",
       " '__delitem__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__getitem__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__iadd__',\n",
       " '__imul__',\n",
       " '__init__',\n",
       " '__iter__',\n",
       " '__le__',\n",
       " '__len__',\n",
       " '__lt__',\n",
       " '__mul__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__reversed__',\n",
       " '__rmul__',\n",
       " '__setattr__',\n",
       " '__setitem__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " 'append',\n",
       " 'clear',\n",
       " 'copy',\n",
       " 'count',\n",
       " 'extend',\n",
       " 'index',\n",
       " 'insert',\n",
       " 'pop',\n",
       " 'remove',\n",
       " 'reverse',\n",
       " 'sort']"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir(list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这些方法分为两大类：**（注意：list把自己管理的对象称为item）**  \n",
    "\n",
    "\n",
    "1. 隐藏方法。即名字前面和后面是两个“_”。（list并不是不想让我们用隐藏的方法，而是有“语法蜜糖”，不想让我们麻烦）。\n",
    "2. 非隐藏方法。建议直接使用。\n",
    "  \n",
    "从每个方法的名字，我们就可以猜出其功能。我们可以试一下：\n",
    "- `__delitem__` : 从仓库中删除一个对象。（什么是删除？该有疑问：是从仓库中去除，还是灭了它？，这里是前者。）\n",
    "- `append,add,insert`: 这些应该都是往仓库中添加对象，只是放的位置不同。\n",
    "- `index,reverse,sort `: 明显与仓库中的对象顺序有关。\n",
    "- `__mul__`:你可能会困惑，因为我们在int对象中见过，该方法代表乘法。难道list能相乘吗？其实这里是指对仓库扩容，如一个list\\*2，将会把仓库内的对象都复制一个，并添加进去，使仓库类的对象数量增加一倍。这种思想在面向对象中称为多态性（即同样是乘法，对int，就是数量翻倍，对list，却是其中的对象翻倍）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1 创建与访问\n",
    "\n",
    "\n",
    "创建一个list对象的语法很简单，只需要将几个对象的名字放入方括号中，就能生成一个list对象（当然不要忘了给她一个名字，不然你就再也看不到她了）。list中的对象是有顺序的，按照这种顺序，可以给每一个对象一个编号，称为下标。第一个对象的下标规定为0，依次类推。另外，list也支持用负数作为下标。规定最后一个对象的下标是-1，倒数第二个对象的下标是-2，依次类推。使用下标，可以找到和使用list中的每一个对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class1 type is<class 'list'>\n",
      "there are 4 students in this class\n",
      "there are 4 students in this class\n",
      "the first student is zhangsan\n",
      "the first student is zhangsan\n",
      "the second student is wangwu\n",
      "the last student is lisi\n",
      "the last student is lisi\n",
      "the last one student is wangwu\n",
      "the num is 20200909\n",
      "the name is zhangsan\n",
      "the sex is True\n",
      "the score of math is 100\n"
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/introduction.py\n",
    "#introduction.py\n",
    "\n",
    "# 创建对象\n",
    "class1 = ['zhangsan','wangwu','wangwu','lisi']\n",
    "print('class1 type is{}'.format(type(class1)))\n",
    "\n",
    "# 获取对象数目\n",
    "len1 = class1.__len__()\n",
    "print('there are {} students in this class'.format(len1))\n",
    "len2 = len(class1)     #语法蜜糖\n",
    "print('there are {} students in this class'.format(len2))\n",
    "\n",
    "# 获得对象\n",
    "first1 = class1.__getitem__(0)\n",
    "print('the first student is {}'.format(first1))\n",
    "\n",
    "first2 = class1[0]     #语法蜜糖\n",
    "print('the first student is {}'.format(first2))\n",
    "\n",
    "#反向编号\n",
    "print('the second student is {}'.format(class1[1]))\n",
    "print('the last student is {}'.format(class1[3]))\n",
    "print('the last student is {}'.format(class1[-1]))\n",
    "print('the last one student is {}'.format(class1[-2]))\n",
    "\n",
    "\n",
    "#不同类型的对象\n",
    "student1 = [20200909,'zhangsan',True,100,80]\n",
    "print('the num is {}'.format(student1[0]))\n",
    "print('the name is {}'.format(student1[1]))\n",
    "print('the sex is {}'.format(student1[2]))\n",
    "print('the score of math is {}'.format(student1[3]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "list中的对象可以是任意类型的对象。当一个list中的一个或多个对象是list对象时，称为嵌套。尽管开始可能觉得有点烧脑，但这正是list的强大之处。看下面的代码体会一下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "there are 4 students in this class\n",
      "first student's name is zhangsan\n",
      "second student's num is 20200902\n"
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/l2nest.py\n",
    "#nest.py\n",
    "student1 = [20200901,'zhangsan',True,100,80]\n",
    "student2 = [20200902,'lisi',False,90,80]\n",
    "student3 = [20200903,'wangwu',True,70,80]\n",
    "student4 = [20200904,'zhaoliu',True,50,80]\n",
    "class1 = [student1,student2,student3,student4]\n",
    "print('there are {} students in this class'.format(class1.__len__()))\n",
    "first = class1[0]\n",
    "first_name = first[1]\n",
    "print(\"first student's name is {}\".format(first_name))\n",
    "print(\"second student's num is {}\".format(class1[1][0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 遍历\n",
    "既然list中的对象是按照顺序存放，因此就可以按照顺序（分为正向和反向）访问每一个对象，这样的操作称为遍历。遍历的方法可以分为两类：\n",
    "- 采用for循环遍历\n",
    "- 使用下标遍历\n",
    "\n",
    "### 2.1 for循环遍历\n",
    "这是python针对如list等一类对象（这类对象称为可遍历对象，它们共同的特点是含有可排序的多个对象）提供的特别语法，使用简单，但在这里无法进行反向遍历。举例代码如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "there are 4 student in this class:\n",
      "zhangsan wangwu wangwu lisi "
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/traverse1.py\n",
    "#travese1.py\n",
    "# 创建对象\n",
    "class1 = ['zhangsan','wangwu','wangwu','lisi']\n",
    "print('there are {} student in this class:'.format(class1.__len__()))\n",
    "# for遍历\n",
    "for student in class1:\n",
    "    print(student,end=' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意，每一次进入第8行的语句块中时，student名字所指的对象都不相同。会按照顺序，分别指向class1中的每一个对象，从而完成遍历。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 下标遍历\n",
    "利用list中对象的下标，也可以完成对list的遍历。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "there are 4 student in this class:\n",
      "\n",
      "下标正向遍历\n",
      "\n",
      "zhangsan lisi wangwu zhaoliu \n",
      "下标反向遍历\n",
      "\n",
      "zhaoliu wangwu lisi zhangsan "
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/traverse2.py\n",
    "#travese2.py\n",
    "class1 = ['zhangsan','lisi','wangwu','zhaoliu']\n",
    "print('there are {} student in this class:'.format(class1.__len__()))\n",
    "\n",
    "print('\\n下标正向遍历\\n')\n",
    "current = 0;\n",
    "last = len(class1) -1\n",
    "while current <= last:\n",
    "    student = class1[current]\n",
    "    print(student,end=' ')\n",
    "    current = current + 1\n",
    "\n",
    "print('\\n下标反向遍历\\n')\n",
    "current = len(class1) -1\n",
    "last = 0\n",
    "while current >= last:\n",
    "    student = class1[current]\n",
    "    print(student,end=' ')\n",
    "    current = current - 1    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`range`函数是python的内建函数，可以为我们快速生成一个由整数（包括负数）构成的list对象。其调用参数为：\n",
    "```python \n",
    "range(start,end,step)\n",
    "```\n",
    "range生成的list，其实是一个由start开始，步长为step的等差序列。\n",
    ">什么是等差序列呢？如：1,3,5,7就是一个长度为4的等差序列，它的相邻的两个数字之间的差值（称为步长）都相同（都是2）。步长为正的，称为递增等差序列；步长为负的，称为递减等差序列。\n",
    "\n",
    "- start: 序列的第一个数。\n",
    "- step: 序列步长。表示相邻两个整数的差。 \n",
    "- end：序列边界。当step为正数时，list是一个递增序列，end就是序列的上界；当step为负数时，list是一个递减序列，那end就是序列的下界。**特别注意，序列中不包含end**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "递增序列\n",
      "1 2 3 4 \n",
      "递减序列\n",
      "5 4 3 2 "
     ]
    }
   ],
   "source": [
    "print('递增序列')\n",
    "list1 = range(1,5,1)\n",
    "for i in list1:\n",
    "    print(i,end=' ')\n",
    "print('\\n递减序列')\n",
    "list2 = range(5,1,-1)\n",
    "for i in list2:\n",
    "    print(i,end=' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个函数在调用时，有些参数可以不写，有默认值。这些默认值也比较合理。如step默认就是1，start默认是0。\n",
    "\n",
    "\n",
    "掌握了range函数，我们就可以用它来生成下标，对list进行遍历。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "there are 4 student in this class:\n",
      "\n",
      "下标正向遍历\n",
      "\n",
      "zhangsan lisi wangwu zhaoliu \n",
      "下标反向遍历\n",
      "\n",
      "zhaoliu wangwu lisi zhangsan "
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/traverse3.py\n",
    "#travese3.py\n",
    "class1 = ['zhangsan','lisi','wangwu','zhaoliu']\n",
    "print('there are {} student in this class:'.format(class1.__len__()))\n",
    "\n",
    "print('\\n下标正向遍历\\n')\n",
    "my_list = range(0,len(class1))\n",
    "for i in my_list:\n",
    "    student = class1[i]\n",
    "    print(student,end=' ')\n",
    "\n",
    "print('\\n下标反向遍历\\n')\n",
    "my_list = range(len(class1)-1,-1,-1)\n",
    "for i in my_list:\n",
    "    student = class1[i]\n",
    "    print(student,end=' ')\n",
    "    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里我们定义一个遍历函数，便于后面的演示代码使用："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "def traverse(plist):\n",
    "    print(\"\\nthere are {} items in this list\".format(len(plist)))\n",
    "    for i in plist:\n",
    "        print(i,end=' ')\n",
    "    print('\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 修改\n",
    "前面的操作，都不会对list对象造成任何改变。而下面的操作，则会造成list对象改变。这些改变可以分为两类：\n",
    "- 造成list包含的对象的增减。\n",
    "- 造成list中对象的顺序发生变化。\n",
    "### 3.1 对象增减"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "there are 4 student in this class:\n",
      "zhangyi lisi wangwu zhaoliu \n",
      "\n",
      "zhangyi liwu wangwu zhaoliu \n",
      "\n",
      "zhangyi wangwu zhaoliu \n",
      "\n",
      "zhangyi zhaoliu \n",
      "\n",
      "zhangyi lisi zhaoliu \n",
      "\n",
      "zhangyi lisi zhaoliu wangwu \n",
      "\n",
      "zhangyi lisi zhaoliu \n",
      "\n",
      "wangwu\n",
      "zhangyi zhaoliu \n",
      "\n",
      "wangwu\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/edit.py\n",
    "#edit.py\n",
    "def traverse(plist):\n",
    "    for i in plist:\n",
    "        print(i, end = ' ')\n",
    "    print('\\n')\n",
    "    \n",
    "class1 = ['zhangsan','lisi','wangwu','zhaoliu']\n",
    "print('there are {} student in this class:'.format(class1.__len__()))\n",
    "\n",
    "#替换下标位置上的对象\n",
    "class1.__setitem__(0,'zhangyi') #调用方法\n",
    "traverse(class1)\n",
    "class1[1] = 'liwu' #语法蜜糖\n",
    "traverse(class1)\n",
    "\n",
    "#删除下标位置上的对象，注意，后面对象的下标会减1。\n",
    "class1.__delitem__(1)\n",
    "traverse(class1)\n",
    "del class1[1]    #语法蜜糖\n",
    "traverse(class1)\n",
    "\n",
    "#插入对象\n",
    "class1.insert(1,'lisi')\n",
    "traverse(class1)\n",
    "\n",
    "#追加对象\n",
    "class1.append('wangwu')\n",
    "traverse(class1)\n",
    "\n",
    "#弹出对象\n",
    "student = class1.pop()\n",
    "traverse(class1)\n",
    "print(student)\n",
    "\n",
    "#删除一个对象\n",
    "class1.remove(\"lisi\")\n",
    "traverse(class1)\n",
    "print(student)\n",
    "\n",
    "\n",
    "#清空所有对象\n",
    "class1.clear()\n",
    "traverse(class1)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 改变顺序\n",
    "即改变list中全体或部分对象的下标。看下面的代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "zhangsan lisi wangwu zhaoliu \n",
      "\n",
      "zhaoliu wangwu lisi zhangsan \n",
      "\n",
      "zhaoliu zhangsan wangwu lisi \n",
      "\n",
      "lisi wangwu zhangsan zhaoliu \n",
      "\n"
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/seqTest.py\n",
    "#seqTest.py\n",
    "class1 = ['zhangsan','lisi','wangwu','zhaoliu']\n",
    "traverse(class1)\n",
    "\n",
    "class1.reverse()\n",
    "traverse(class1)\n",
    "\n",
    "class1.sort(reverse = True)\n",
    "traverse(class1)\n",
    "\n",
    "class1.sort(reverse = False)\n",
    "traverse(class1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意reverse和sort的区别：\n",
    "- 前者对所有的对象下标进行翻转\n",
    "- 后者是按照不同对象的顺序进行排序，所以对象必须可排序才可以。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 查找\n",
    "就是检索某个对象是否包含在list中，并找到该对象的下标。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "zhangsan lisi wangwu zhaoliu \n",
      "\n",
      "lisi's index is 1\n",
      "lisi' times is 1\n",
      "zhangsan wangwu zhaoliu \n",
      "\n"
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/find.py\n",
    "#find.py\n",
    "class1 = ['zhangsan','lisi','wangwu','zhaoliu']\n",
    "traverse(class1)\n",
    "\n",
    "i = class1.index('lisi') #查找对象“lisi”，返回其下标。当有多个该对象时，只返回第一个的下标\n",
    "print(\"lisi's index is {}\".format(i))\n",
    "i = class1.count('lisi') #返回对象“lisi”在列表中的出现次数\n",
    "print(\"lisi' times is {}\".format(i))\n",
    "\n",
    "i = class1.remove('lisi') #查找对象“lisi”并从列表中删除。\n",
    "traverse(class1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 第7行：获得list中第一个‘lisi’的下标。\n",
    "- 第9行：获得list中‘lisi’对象的数目\n",
    "- 第13行：删除找到的第一个‘lisi’对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 复制与切片\n",
    "\n",
    "\n",
    "从list中通过下标选择部分或全部对象，构成一个新的list对象，称为copy操作。list为此提拱了一个方法，名字为copy。由于copy操作在数据处理中使用很多，因此，python为此提供了语法蜜糖，称为切片操作，意思是从list中选取部分对象构成一个新的list对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "there are 4 student in this class:\n",
      "zhangsan lisi wangwu zhaoliu \n",
      "\n",
      "zhangsan lisi wangwu zhaoliu \n",
      "\n",
      "xingjiu lisi wangwu zhaoliu \n",
      "\n",
      "lisi wangwu \n",
      "\n",
      "xingjiu lisi wangwu zhaoliu \n",
      "\n",
      "xingjiu lisi wangwu \n",
      "\n",
      "lisi wangwu zhaoliu \n",
      "\n",
      "zhaoliu wangwu \n",
      "\n"
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/copys.py\n",
    "#copys.py\n",
    "class1 = ['zhangsan','lisi','wangwu','zhaoliu']\n",
    "print('there are {} student in this class:'.format(class1.__len__()))\n",
    "traverse(class1)\n",
    "class2 = class1.copy()  ##复制操作\n",
    "class1[0] =('xingjiu') \n",
    "traverse(class2)\n",
    "traverse(class1)\n",
    "\n",
    "class2 = class1[1:3]   #切片操作，下面是各种使用缺省值的使用方法\n",
    "traverse(class2)\n",
    "\n",
    "class2 = class1[:]\n",
    "traverse(class2)\n",
    "\n",
    "class2 = class1[:3]\n",
    "traverse(class2)\n",
    "\n",
    "class2 = class1[1:]\n",
    "traverse(class2)\n",
    "\n",
    "class2 = class1[3:1:-1]  #反向切片，因为步长为负。注意看结果中对象的顺序\n",
    "traverse(class2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5 体现多态性的方法\n",
    "通过`dir(list)`，我们看到list的一些方法和`int`对象的方法一样，这称为多态性，即不同类别的对象，却具有相同的功能（对象的功能必须且只能通过方法展示出来）。但是，这些功能的实现却会展现出对象各自的特色。如int的加法就是算数加法，而list的加法，却表示将两个list合并。这里举几个例子，注意体会："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 1, 2, 3]\n",
      "1 2 1 2 \n",
      "\n",
      "1 2 1 2 \n",
      "\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "# %%writefile aboutList/others.py\n",
    "#others.py\n",
    "l1 = [1,2]\n",
    "l2 = [1,2,3]\n",
    "l3 = l1 + l2  #加法，语法蜜糖，你知道对应的方法是什么吗？\n",
    "print(l3)\n",
    "\n",
    "#list的乘法\n",
    "l3 = l1.__mul__(2)\n",
    "traverse(l3)\n",
    "l4 = l1 * 2  #语法蜜糖\n",
    "traverse(l4)\n",
    "\n",
    "#比较大小\n",
    "print(l1<l2) # 语法蜜糖    \n",
    "print(l1.__lt__(l2))  #对应的方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面第14行的比较大小操作过程如下：\n",
    "1. 将l1中的对象与l2中的对象按照下标对齐。\n",
    "2. 从下标0开始，两个list中的同下标的对象比较大小，直到定出大小。\n",
    "\n",
    "\n",
    "其它几个比较操作与此相同。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6 几个特殊的list\n",
    "在python，有两个类与list非常相似，它们是str和tuple。\n",
    "### 6.1 str就是特殊的的list\n",
    "str对象也是由多个对象按照顺排列，只不过这些对象只能是字符（可以看作是长度为1的str对象）。但str属于不可变对象，因此对一个str对象，list中除了修改操作外，其它的方法都可以应用到str。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "1\n",
      "1\n",
      "\n",
      "for遍历\n",
      "\n",
      "1 2 3 \n",
      "下标遍历\n",
      "\n",
      "1 2 3 "
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/str_as_list.py\n",
    "#str_as_list.py\n",
    "s = '123'\n",
    "print(s.__len__())\n",
    "print(s.index('2'))\n",
    "print(s[0])\n",
    "\n",
    "print('\\nfor遍历\\n')\n",
    "for i in s:\n",
    "    print(i,end = ' ')\n",
    "\n",
    "print('\\n下标遍历\\n')\n",
    "\n",
    "for i in range(0,len(s)):\n",
    "    print(s[i],end = ' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.2 tuple就是不可变的list\n",
    "tupel对象,称为元组对象。它和list几乎完全一样，也是将一批对象按照顺序排列，唯一的区别是，元组对象是不可变的。因此对一个元组对象，list中除了修改操作外，其它的方法都可以应用。\n",
    "> 重点：一个对象的可变与不可变，完全由对象的方法决定。当一个对象提供了更改自己的方法，那该对象就是可变对象，如list对象；一个对象没有提供更改自己的方法，那该对象就是不可变对象。如int，bool，和str等。\n",
    "\n",
    "定义一个元组对象语法简单，将几个对象用圆括号“（）”括起来，就能生成一个元组对象。当然不要忘了给该元组对象命个名字。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'tuple'>\n",
      "1 2 zhao\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "t = (1,2,'zhao')\n",
    "print(type(t))\n",
    "print(t[0],t[1],t[2])\n",
    "print(len(t))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意，当元组只包含一个对象时，定义语法有些特殊，必须在该对象后面加一个逗号“，”。如下面的例子，注意看`t1` 和`t2`的类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'int'> <class 'tuple'>\n"
     ]
    }
   ],
   "source": [
    "t1 = (1)\n",
    "t2 = (1,)\n",
    "print(type(t1),type(t2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你只要站在解释器的角度，这个其实很好理解。如果没有逗号，解释器就不知道你是在定义一个int对象，还是在定义一个包含了int对象的tuple对象。\n",
    "\n",
    "\n",
    "作为不可变的list，尽管tuple几乎具有list的所有功能，但两者的使用场景却有很大的区别：list主要用于保存和管理对象，tuple则主要用于在函数（或方法）内外传递对象。下面给出tuple的两个典型用法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 20 30\n",
      "20 10\n",
      "(2, 3)\n"
     ]
    }
   ],
   "source": [
    "#%%writefile aboutList/tuple_as_list.py\n",
    "#tuple_as_list.py\n",
    "a,b,c = 10,20,30\n",
    "print(a,b,c)\n",
    "\n",
    "a,b = b,a\n",
    "print(a,b)\n",
    "\n",
    "def f1(a,b):\n",
    "    return a+1,b+1\n",
    "r = f1(1,2)\n",
    "print(r)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "代码的第3行语法，实现了多个对象的同时命名。另外，你能理解第6行代码吗？结果是交换了两个对象的名字。\n",
    "9到12行代码演示了函数如何返回多个对象。按照语法规则，一个函数只能返回一个对象。如果有函数需要返回多个对象，就可以把这些对象做成一个tuple对象返回，从而实现返回多个对象的目的。注意，第9行可以看作是语法蜜糖，等于下面的多行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "'return' outside function (<ipython-input-65-e91d022e9a8f>, line 2)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-65-e91d022e9a8f>\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m    return t\u001b[0m\n\u001b[0m            ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m 'return' outside function\n"
     ]
    }
   ],
   "source": [
    "t = (a+1,b+1)\n",
    "return t"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7 一个奇怪而常用的语法蜜糖\n",
    "看下面的代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list1 = [ i * 2 for i in range(10)]\n",
    "traverse(list1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第一句是不是看着有点奇怪，其实这是一个语法蜜糖，等于下面的写法，也就是说，解释器看着也觉得难受，它会将其转化为下面的前三行代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list1 = []\n",
    "for i in range(10):\n",
    "    list1.append(i * 2)\n",
    "traverse(list1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "两者的执行效果完全一样，都是生成一个新的list。这个语句称为列表的生成式语法，是一个特殊的语法，其实也就是一个语法蜜糖。它存在的理由就是，熟练的python程序员在生成列表时，觉得这个语法简洁。注意，这个生成式语法可以更复杂，遵循下面的限制：\n",
    "1. for循环可以嵌套，但只能嵌套一次。也就是最多只能是嵌套的两个for循环。\n",
    "2. 第一项可以使用表达式。\n",
    "\n",
    "看下面的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list1 = [a*b for a in range(10) for b in range(10)]\n",
    "traverse(list1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的列表list1，包含了乘法表的所有项，共有$9\\times9 = 81$项。我只告诉你上面的第1行是下面的1到4行的语法蜜糖，你就会理解它为什么会得到这个结果，当然也会体会到这个语法蜜糖存在的必要性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = []\n",
    "for a in range(10):\n",
    "    for b in range(10):\n",
    "        l.append(a * b)\n",
    "traverse(l)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8 总结\n",
    "list是python提供的一个重要的集合类对象。在程序设计中，如果要管理多个对象，你应该马上想到她。\n",
    "\n",
    "\n",
    "另外，str对象其实是一个只包含长度为1的str对象的不可变的list对象；tuple则直接是list的不可变版本，当你需要在函数内外之间传递对象时，应该想到她。\n",
    "\n",
    "\n",
    "最后，还是记住：\n",
    "- python中，一个对象的所有功能，只能也只有通过其方法来实现。\n",
    "- 学习对象的功能，就是学习其方法。\n",
    "- 方法和函数很像，但不一样。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
